// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __PLANETARYSCENEMANAGER_H_
#define __PLANETARYSCENEMANAGER_H_

#include <vector>

#include <OgreOctreeSceneManager.h>
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include "planetarybody.h"

namespace Ogre
{
	class PlanetaryOptions;
	class PlanetaryHeightmapData;
	class PlanetaryPlanet;
	class PlanetaryIndexBufferManager;

	/**
	* Factory for PlanetarySceneManager.
	* Used by OGRE to create an instance of the scene manager.
	*/
	class PlanetarySceneManagerFactory : public SceneManagerFactory
	{
	protected:
		void initMetaData(void) const;
	public:
		PlanetarySceneManagerFactory() {}
		~PlanetarySceneManagerFactory() {}

		/// Factory type name
		static const String FACTORY_TYPE_NAME;
		SceneManager* createInstance(const String& instanceName);
		void destroyInstance(SceneManager* instance);
	};

	/**
	* The core class of the Planetary Scene Manager.
	* This class starts the loading of a new world. Othere entities are handled by the base class OctreeSceneManager
	*/
	class PlanetarySceneManager : public OctreeSceneManager
	{
	public:
		PlanetarySceneManager(const String &name);
		~PlanetarySceneManager();

		// Loads the world geometry
		/// Starts the loading of world geometry.
		/// @param filename File to load configuration options from
		void setWorldGeometry(const String &filename);
		/// Starts the loading of world geometry
		/// @param stream Stream to the file or resource that contains the configuration options for this world
		void setWorldGeometry(DataStreamPtr &stream, const String &typeName = StringUtil::BLANK);
		
		/// Creates a specialised camera
		virtual Camera* createCamera(const String &name);
		
		/// Retrieves a list of planetary bodies used for calculation gravity
		std::vector<PlanetaryBody*> getPlanetaryBodies();

		/// Retrieves the options object
		inline PlanetaryOptions *getOptions()
		{
			return mOptions;
		}

		/// Get a pointer to the PlanetaryHeightmapData instance
		inline PlanetaryHeightmapData *getHeightmapData()
		{
			return mHeightmapData;
		}
		
		/// Clears the scene of all terrain and objects
		void clearScene();
		
		/// Returns the active camera used in rendering operations
		inline Camera* getActiveCamera()
		{
			return mCameraInProgress;
		}

		/// Returns a pointer to the PlanetaryIndexBufferManager instance
		inline PlanetaryIndexBufferManager *getIndexBufferManager()
		{
			return mIndexBufferMgr;
		}

		/// Sets the dynamics world (bullet) and enables terrain collisions
		inline void setDynamicsWorld(btDynamicsWorld* world)
		{
			mWorld = world;
			mBulletPhysicsEnabled = true;
		}

		/// Returns the previously set dynamics world (bullet)
		inline btDynamicsWorld* getDynamicsWorld()
		{
			return mWorld;
		}
		/// Returns true if terrain collision is enabled (bullet)
		inline bool isBulletPhysicsEnabled()
		{
			return mBulletPhysicsEnabled;
		}

	protected:
		/// Test Planet object
		PlanetaryPlanet *mPlanet;

		/// Class containing all options
		PlanetaryOptions *mOptions;

		/// Class managing heightmap data
		PlanetaryHeightmapData *mHeightmapData;

		/// Class managing index buffers
		PlanetaryIndexBufferManager *mIndexBufferMgr;

		/// Keep track of world geometry status
		bool mWorldGeometryIsSetup;

		btDynamicsWorld	*mWorld;        		/**< physics world object (Bullet) */
		bool mBulletPhysicsEnabled;
	};
}

#endif
